/*---------------------------------------------------------------------------
// 
//  File:  sas.c
//  Purpose:  Host Universal Architecture: sas resource
//  History:  2013-08-26 Created by  
//
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <memory.h>
#include "sm_trace.h"
#include "itc.h"
#include "app_proxy.h"
#include "sas.h"

sas_data_t s_stSas = {0};
unsigned int s_isSasSessOpened;
unsigned char sasAppId[8] = {0x53,0x4d,0x69,0x54,0x5a,0x42,0x4a,0x4c};// SMiTZBJL

sm_queue_t	s_queSasTuner;
sm_queue_t	s_queSasPid;
sm_queue_t	s_queSasUpgrade;
sm_queue_t	s_queSasDongleType;
sm_queue_t  s_queSasdonglHW;
sm_queue_t  s_queSasMmiAbility;

sm_sem_t 	s_semSasTuner;
sm_sem_t 	s_semSasdongletype;
sm_sem_t	s_semSasPid;
sm_sem_t	s_semSasUpgrade;
sm_sem_t	s_semSasDongleHW;
sm_sem_t	s_semSasDongleMmi;


static unsigned char s_sasConnected;
unsigned long sastest_taskID;

static pfSasSessionConnected pfSasSessionConnectedCb = NULL;

int sas_task(void* pParam);
static int SasCheckSessActive(unsigned short u16SlotId, short u16Ssnb);


static unsigned int SasAllocSessionIndex()
{
	unsigned int i;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasAllocSessionIndex entry. r\n");
	for(i=0; i<CIEHS_SAS_MAX_SESSION_NUM; i++)
	{
		if(s_stSas.m_astAppSess[i].m_eStatus == CIEHS_APP_SESS_FREE)
			break;
	}

	if(i >= CIEHS_SAS_MAX_SESSION_NUM)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasAllocSessionIndex allocate session index fail\r\n");
		i = CIEHS_SAS_INVALID_SESSION_INDEX;
	}
	SM_TRACE_RETURN(TRMOD_SAS, "SasAllocSessionIndex return allocate slot = %d\r\n", i);

	return i;
}

static unsigned int SasFindSessionIndex(unsigned short u16SlotId, unsigned short u16Ssnb)
{
	unsigned int i;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasFindSessionIndex entry. r\n");
	for(i=0; i<CIEHS_SAS_MAX_SESSION_NUM; i++)
	{
		if(s_stSas.m_astAppSess[i].m_eStatus != CIEHS_APP_SESS_FREE 
			&& s_stSas.m_astAppSess[i].m_u8Slotid == u16SlotId
			&& s_stSas.m_astAppSess[i].m_u16Ssnb == u16Ssnb)
			break;
	}

	if(i >= CIEHS_SAS_MAX_SESSION_NUM)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasFindSessionIndex() - found session index fail\r\n");
		i = CIEHS_SAS_INVALID_SESSION_INDEX;
	}
	SM_TRACE_RETURN(TRMOD_SAS, "SasFindSessionIndex() - return allocate slot = %d\r\n", i);

	return i;
}

static unsigned int SasFindSpareSessIndex(unsigned char u8SlotId)
{
	unsigned int i;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasFindSpareSessIndex entry. r\n");
	for(i=0; i<CIEHS_SAS_MAX_SESSION_NUM; i++)
	{
		if(s_stSas.m_astAppSess[i].m_eStatus == CIEHS_APP_SESS_SPARE 
			&& s_stSas.m_astAppSess[i].m_u8Slotid == u8SlotId)
			break;
	}

	if(i < CIEHS_SAS_MAX_SESSION_NUM)
	{
		SM_TRACE_INFO(TRMOD_SAS, "SasFindSpareSessIndex() - found spare session index %d\r\n", i);	
	}
	else
	{
		SM_TRACE_INFO(TRMOD_SAS, "SasFindSpareSessIndex() - spare session not found\r\n");	
		i = CIEHS_SAS_INVALID_SESSION_INDEX;
	}

	SM_TRACE_RETURN(TRMOD_SAS, "SasFindSpareSessIndex return allocate slot = %d\r\n", i);

	return i;
}

void SendSasResourceAPDU(unsigned char u8CISlot, unsigned short u16SessionNB,
							 const unsigned char*pu8APDUData, unsigned int u32APDULen)//Send APDU of Private Resource to CICAM. 
{
	xmsg_t		xmsg;
	int			apduLen;

	memset(&xmsg, 0x00, sizeof(xmsg));
	apduLen = u32APDULen;
	xmsg.m_bd.m_app_apdu.m_pbApdu = ITC_DynAlloc(apduLen);
	if (xmsg.m_bd.m_app_apdu.m_pbApdu == NULL)
	{
		SM_TRACE_INFO(TRMOD_SAS,"SendSasResourceAPDU() - mem alloc error");
		return;
	}

	xmsg.m_sndrcver = (RM << 4) | RM;
	xmsg.m_type  = APP_APDU;
	xmsg.m_bd.m_app_apdu.m_ssnb = u16SessionNB;
	xmsg.m_bd.m_app_apdu.m_apduLen = apduLen;
	memcpy(xmsg.m_bd.m_app_apdu.m_pbApdu, pu8APDUData, apduLen);

	ITC_SendXmsg(&xmsg);
}



/******************************************************************************
  函数名: SasSessClose()
  描述:   处理CAM打开会话请求
  其他:
******************************************************************************/
static int SasSessConnect(unsigned char u8SlotId, unsigned short u16Ssnb)
{
	unsigned int index;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSessConnect entry u32SlotId = %d, u32Ssnb = %d\r\n", u8SlotId, u16Ssnb);
	if(u8SlotId > MAXSLOTID)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSessConnect found u32SlotId error\r\n");
		return -1;
	}

	SM_OsSemWait(&s_stSas.m_semLock, -1);

	for(index=0; index<CIEHS_SAS_MAX_SESSION_NUM; index++)
	{
		if(s_stSas.m_astAppSess[index].m_eStatus != CIEHS_APP_SESS_FREE)
		{
			break;
		}
	}
	
	//index = CIEHS_SAS_INVALID_SESSION_INDEX;
	index = SasFindSpareSessIndex(u8SlotId);
	if(index == CIEHS_SAS_INVALID_SESSION_INDEX)
	{
		index = SasAllocSessionIndex();
		if(index != CIEHS_SAS_INVALID_SESSION_INDEX)
		{
			s_stSas.m_astAppSess[index].m_eStatus = CIEHS_APP_SESS_SPARE;
			s_stSas.m_astAppSess[index].m_u8Slotid = u8SlotId;
			s_stSas.m_astAppSess[index].m_u16Ssnb = u16Ssnb;
			s_stSas.m_astAppSess[index].m_u32Instid = CIEHS_SAS_INVALID_PLUGIN_INSTANCE;
			memset(s_stSas.m_astAppSess[index].m_au8AppId, 0, sizeof(s_stSas.m_astAppSess[index].m_au8AppId));
			SM_TRACE_NOTIFY(TRMOD_SAS, "SasSessConnect() - the connection to spare session %d estabilish successfully\r\n", u16Ssnb);
		}
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSessConnect() - found slot %d spare session has estabilish\r\n", u8SlotId);
	}
	
	SM_OsSemRelease(&s_stSas.m_semLock);

	SM_TRACE_RETURN(TRMOD_SAS, "SasSessConnect() - return\r\n");
	return 0;
}

/******************************************************************************
  函数名: SasSessClose()
  描述:   被动关闭SAS会话，即处理CAM关闭会话请求
  其他:
******************************************************************************/
static int SasSessClose(unsigned short u16SlotId, short u16Ssnb)
{
	unsigned int index;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSessClose entry u32SlotId = %d, u32Ssnb = %d\r\n", u16SlotId, u16Ssnb);
	if(u16SlotId > MAXSLOTID)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSessClose found u32SlotId error\r\n");
		return -1;
	}

	SM_OsSemWait(&s_stSas.m_semLock, -1);
	index = SasFindSessionIndex(u16SlotId, u16Ssnb);
	if(index != CIEHS_SAS_INVALID_SESSION_INDEX)
	{
		//reclaim resource
		s_stSas.m_astAppSess[index].m_eStatus = CIEHS_APP_SESS_FREE;
		s_stSas.m_astAppSess[index].m_u32Instid = CIEHS_SAS_INVALID_PLUGIN_INSTANCE;
		memset(s_stSas.m_astAppSess[index].m_au8AppId, 0, CIEHS_SAS_MAX_APPLICATION_ID_LEN);
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSessClose session not found u16SlotId = %d, u16Ssnb = %d", u16SlotId, u16Ssnb);
	}
	SM_OsSemRelease(&s_stSas.m_semLock);

	SM_TRACE_RETURN(TRMOD_SAS, "SasSessClose return\r\n");
	return 0;
}

/******************************************************************************
  函数名: SasSendConnectReqAPDU()
  描述:   向CAM发送sas连接请求APDU
  其他:
******************************************************************************/
static int SasSendConnectReqAPDU(unsigned char u8SlotId, unsigned char au8AppId[], ciehs_instid_t u32Instid)
{
	unsigned int u32SpareIndex;
	unsigned char au8Apdu[12];
	int rc = -1;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSendConnectReqAPDU entry u8SlotId = %d, au8AppId = %s, u32Instid = %d\r\n", u8SlotId, au8AppId, u32Instid);
	u32SpareIndex = SasFindSpareSessIndex(u8SlotId);
	if(u32SpareIndex != CIEHS_SAS_INVALID_SESSION_INDEX)
	{
		memcpy(s_stSas.m_astAppSess[u32SpareIndex].m_au8AppId, au8AppId, CIEHS_SAS_MAX_APPLICATION_ID_LEN);
		s_stSas.m_astAppSess[u32SpareIndex].m_u32Instid = u32Instid;
		s_stSas.m_astAppSess[u32SpareIndex].m_eStatus = CIEHS_APP_SESS_CONNECT_REQ;
		//s_stSas.m_astAppSess[u32SpareIndex].m_u32PluginThreadMsgqueueKey = u32PluginThreadMsgqueueKey;
		asnWriteInt24(au8Apdu, CIEHS_SAS_TAG_CONNECT_REQ);
		asnWriteApduLengthField(&au8Apdu[3], CIEHS_SAS_MAX_APPLICATION_ID_LEN);
		memcpy(&au8Apdu[4], au8AppId, CIEHS_SAS_MAX_APPLICATION_ID_LEN);
		SendSasResourceAPDU(s_stSas.m_astAppSess[u32SpareIndex].m_u8Slotid, s_stSas.m_astAppSess[u32SpareIndex].m_u16Ssnb, au8Apdu, sizeof(au8Apdu));
		rc = OK;
	}
	SM_TRACE_RETURN(TRMOD_SAS, "SasSendConnectReqAPDU return\r\n");
	return rc;
}

/******************************************************************************
  函数名: SasHandleConnectCnfAPDU()
  描述:   处理CAM发送过来的connect confirm 消息
  其他:
******************************************************************************/
static int SasHandleConnectCnfAPDU(unsigned int index, unsigned char* pu8Payload, unsigned int u32Len)
{
	unsigned char u8SessStatus;
	int rc = OK;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasHandleConnectCnfAPDU entry index = %d, pu8Payload = %p, u32Len = %d\r\n", index, pu8Payload, u32Len);
	u8SessStatus = pu8Payload[8];
	if(u8SessStatus == CIEHS_SAS_CONNECT_OK
		&& memcmp(s_stSas.m_astAppSess[index].m_au8AppId, pu8Payload, 8) == 0)
	{
		s_stSas.m_astAppSess[index].m_eStatus = CIEHS_APP_SESS_CONNECT_OK;
		s_sasConnected = 1;//ytdiao
	}
	else if(u8SessStatus == CIEHS_SAS_NO_VENDOR_CARD_APPLICATION 
		|| u8SessStatus == CIEHS_SAS_NO_MORE_CONNECTION)
	{
		if(SasFindSpareSessIndex(s_stSas.m_astAppSess[index].m_u8Slotid) == CIEHS_SAS_INVALID_SESSION_INDEX)
		{
			s_stSas.m_astAppSess[index].m_eStatus = CIEHS_APP_SESS_SPARE;
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS, "SasHandleConnectCnfAPDU receive connect deny found spare session have open\r\n");
			//close deny session
		}
		//try next slot
		if(s_stSas.m_astAppSess[index].m_u8Slotid < MAXSLOTID-1)// need care
		{
			SasSendConnectReqAPDU(s_stSas.m_astAppSess[index].m_u8Slotid+1, s_stSas.m_astAppSess[index].m_au8AppId, s_stSas.m_astAppSess[index].m_u32Instid);
			//free current slot
			s_stSas.m_astAppSess[index].m_eStatus = CIEHS_APP_SESS_FREE;
		}
		else
		{
			SM_TRACE_NOTIFY(TRMOD_SAS, "SasHandleConnectCnfAPDU() -  connect successfully\r\n");
		}
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasHandleConnectCnfAPDU receive error SAS_connect_cnf status %d\r\n", u8SessStatus);
	}
	SM_TRACE_RETURN(TRMOD_SAS, "SasHandleConnectCnfAPDU return\r\n");

	//sastest_taskID = SM_CreateTask("sastest", Sastest_task, NULL, NULL, 5*1024, 81, TRUE, SAS_TASK_AID+1);
	
	return rc;
}


/******************************************************************************
  函数名: SasHandleAsyncMsgAPDU()
  描述    处理CAM发送过来的asyc消息
  其他:
******************************************************************************/
static int SasHandleAsyncMsgAPDU(unsigned int index, unsigned char* pu8Payload, unsigned int u32Len)
{
	int rc = OK;
	unsigned int u32Index = 0;
	unsigned char u8Msgnb;
	unsigned int u32MsgLen;
	sas_async_message_t sas_async_msg;
	
	SM_TRACE_ENTRY(TRMOD_SAS, "SasHandleAsyncMsgAPDU entry index = %d, pu8Payload = %p, u32Len = %d\r\n", index, pu8Payload, u32Len);

	memset(&sas_async_msg, 0, sizeof(sas_async_msg));
	SM_TRACE_BYTES(TRMOD_SAS, TRLEV_NOTIFY, pu8Payload, u32Len>50?50:u32Len, "SasHandleAsyncMsgAPDU() - Async message payload");
	u8Msgnb = pu8Payload[u32Index++];
	u32MsgLen = asnReadInt16(&pu8Payload[1]);
	u32Index += 2;

	sas_async_msg.m_u16Tag = asnReadInt16(&pu8Payload[u32Index]);
	u32Index += 2;

	sas_async_msg.m_u16Len = asnReadInt16(&pu8Payload[u32Index]);
	u32Index += 2;

	SM_TRACE_ERROR(TRMOD_SAS, "SasHandleAsyncMsgAPDU() - u32Len = %d, m_u16Tag = 0x%04x, m_u16Len = %d\r\n", u32Len, sas_async_msg.m_u16Tag, sas_async_msg.m_u16Len);
	sas_async_msg.m_msgBuf = (unsigned char*)malloc(sas_async_msg.m_u16Len);
	if(sas_async_msg.m_msgBuf == NULL)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasHandleAsyncMsgAPDU() - malloc fail!\r\n");
		return -1;
	}

	memcpy(sas_async_msg.m_msgBuf, &pu8Payload[u32Index], sas_async_msg.m_u16Len);

	if(sas_async_msg.m_u16Tag == SAS_PID_LIST_RSP || sas_async_msg.m_u16Tag == SAS_CAM_INFO_RSP)
		SM_SendQueue(&s_queSasPid, &sas_async_msg);
	else if(sas_async_msg.m_u16Tag == SAS_UPGRADE_DATA_RSP)
		SM_SendQueue(&s_queSasUpgrade, &sas_async_msg);
	else if(sas_async_msg.m_u16Tag == SAS_GET_DONGLE_TYPE_RSP)
		SM_SendQueue(&s_queSasDongleType, &sas_async_msg);
	else if(sas_async_msg.m_u16Tag == SAS_UPDATELOG_DATA)
	{
		unsigned int i;
		char* ps8Pos;
		char* ps8Start;
		char s8Tmp;

		ps8Pos = sas_async_msg.m_msgBuf;
		ps8Start = sas_async_msg.m_msgBuf;
		for(i=0; i<sas_async_msg.m_u16Len; i++)
		{
			if(ps8Pos[i] == '\n')
			{
				s8Tmp = ps8Pos[i+1];
				ps8Pos[i+1] = 0;
				SM_TRACE_NOTIFY(TRMOD_SAS, "[dongle]:%s", ps8Start);
				ps8Pos[i+1] = s8Tmp;
				ps8Start = &ps8Pos[i+1];
			}
		}
		free(sas_async_msg.m_msgBuf);
	}
	else if(sas_async_msg.m_u16Tag == SAS_DGL_HW_RSP)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasHandleAsyncMsgAPDU() - dongle hardware info is:%s",sas_async_msg.m_msgBuf);
		SM_SendQueue(&s_queSasdonglHW, &sas_async_msg);
	}
	else if(sas_async_msg.m_u16Tag == SAS_CUS_MMI_RSP)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasHandleAsyncMsgAPDU() - dongle Cus_mmi response type is:%d",sas_async_msg.m_msgBuf[0]);
		SM_SendQueue(&s_queSasMmiAbility, &sas_async_msg);
	}
	else if(sas_async_msg.m_u16Tag == SAS_SC_PLUG_NTF)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasHandleAsyncMsgAPDU() - dongle smart card notify:%d",sas_async_msg.m_msgBuf[0]);
		//DVB_cisasSendSmartcardStatus(sas_async_msg.m_msgBuf);
		free(sas_async_msg.m_msgBuf);
	}
	else
		SM_SendQueue(&s_queSasTuner, &sas_async_msg);

	SM_TRACE_RETURN(TRMOD_SAS, "SasHandleAsyncMsgAPDU() - return rc = %d\r\n", rc);
	return rc;
}

/******************************************************************************
  函数名: SasSessParseAPDU()
  描述:   分析接收到CAM发送过来的SAS APDU
  其他:
******************************************************************************/
static int SasSessParseAPDU(unsigned char u8SlotId, short u16Ssnb, unsigned char* pu8Apdu, unsigned int u32Len)
{
	unsigned int u32SessIndex;
	unsigned int u32ParseIndex;
	unsigned int u32Tag;
	unsigned long u32ApduLen;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSessParseAPDU entry u8SlotId = %d, u16Ssnb = %d, pu8Apdu = %p, u32Len = %d\r\n", u8SlotId, u16Ssnb, pu8Apdu, u32Len);
	if(u8SlotId > MAXSLOTID)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSessParseAPDU found u32SlotId error\r\n");
		return -1;
	}

	SM_OsSemWait(&s_stSas.m_semLock, -1);

	u32SessIndex = SasFindSessionIndex(u8SlotId, u16Ssnb);
	if(u32SessIndex != CIEHS_SAS_INVALID_SESSION_INDEX)
	{
		u32Tag = asnReadInt24(pu8Apdu);
		u32ParseIndex = 3;
		u32ParseIndex += asnReadApduLengthField(&pu8Apdu[3], 4, &u32ApduLen);
		switch(u32Tag)
		{
		case CIEHS_SAS_TAG_CONNECT_CNF:
			SM_TRACE_INFO(TRMOD_SAS, "SasSessParseAPDU receive SAS_connect_cnf\r\n");
			SasHandleConnectCnfAPDU(u32SessIndex, &pu8Apdu[u32ParseIndex], u32ApduLen);
			break;
		case CIEHS_SAS_TAG_ASYNC_MSG:
			SM_TRACE_INFO(TRMOD_SAS, "SasSessParseAPDU receive SAS_async_msg\r\n");
			SasHandleAsyncMsgAPDU(u32SessIndex, &pu8Apdu[u32ParseIndex], u32ApduLen);
			break;
		default:
			SM_TRACE_ERROR(TRMOD_SAS, "SasSessParseAPDU receive error APDU tag\r\n");
			break;
		}
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSessParseAPDU receive msg session not found, u8SlotId = %d, u16Ssnb = %d\r\n", u8SlotId, u16Ssnb);
	}

	SM_OsSemRelease(&s_stSas.m_semLock);
	SM_TRACE_RETURN(TRMOD_SAS, "SasSessParseAPDU return\r\n");
	return 0;
}



int SasSessionOpenReq(unsigned char u8CISlot, unsigned short u16SessionNB)
{
	sas_msg_t stMsg;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSessionOpenReq entry, u8CISlot = %d, u16SessionNB = %d\r\n", u8CISlot, u16SessionNB);
	stMsg.m_u8Slotnb = u8CISlot;
	stMsg.m_u16Ssnb = u16SessionNB;
	stMsg.m_eType = CIEHS_SAS_MESSAGE_TYPE_CONNECT;
	SM_SendQueueByTaskid(s_stSas.m_u32SasTaskid, &stMsg); 
	SM_TRACE_RETURN(TRMOD_SAS, "SasSessionOpenReq return\r\n");

	return OK;
}

void SasAPDURecv(unsigned char u8CISlot, unsigned short u16SessionNB, unsigned char *pu8RxAPDU)
{
	unsigned long u32BodyLen;
	unsigned int u32LenSize;
	sas_msg_t stMsg;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasAPDURecv entry, u8CISlot = %d, u16SessionNB = %d, pu8RxAPDU = %p\r\n", u8CISlot, u16SessionNB, pu8RxAPDU);
	stMsg.m_u8Slotnb = u8CISlot;
	stMsg.m_u16Ssnb = u16SessionNB;
	u32LenSize = asnReadApduLengthField(pu8RxAPDU+3, 4, &u32BodyLen);
	stMsg.m_pu8Apdu = (unsigned char*)malloc(u32BodyLen+3+u32LenSize);
	if(stMsg.m_pu8Apdu)
	{
		memcpy(stMsg.m_pu8Apdu, pu8RxAPDU, u32BodyLen+3+u32LenSize);
		stMsg.m_u32ApduLen = u32BodyLen+3;
		stMsg.m_eType = CIEHS_SAS_MESSAGE_TYPE_DATA;
		SM_SendQueueByTaskid(s_stSas.m_u32SasTaskid, &stMsg); 
	}
}

void SasSessionCloseReq(unsigned char u8CISlot, unsigned short u16SessionNB)
{
	sas_msg_t stMsg;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSessionCloseReq entry, u8CISlot = %d, u16SessionNB = %d\r\n", u8CISlot, u16SessionNB);
	
	stMsg.m_u8Slotnb = u8CISlot;
	stMsg.m_u16Ssnb = u16SessionNB;
	stMsg.m_eType = CIEHS_SAS_MESSAGE_TYPE_CLOSE;
	SM_SendQueueByTaskid(s_stSas.m_u32SasTaskid, &stMsg);

	SM_TRACE_RETURN(TRMOD_SAS, "SasSessionCloseReq return\r\n");
}



/******************************************************************************
  函数名: SasConnectReq()
  描述:   请求建立SAS连接
  其他:
******************************************************************************/
void SasConnectReq(unsigned char au8AppId[], ciehs_instid_t u32Instid)
{
	unsigned int i;
	int rc;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasConnectReq entry, u32Instid = %d\r\n", u32Instid);

	SM_OsSemWait(&s_stSas.m_semLock, -1);
	for(i=0; i<MAXSLOTID; i++)
	{
		rc = SasSendConnectReqAPDU(i, au8AppId, u32Instid);
		if(rc == OK)
		{
			break;
		}
	}
	SM_OsSemRelease(&s_stSas.m_semLock);

	if(i >= MAXSLOTID)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasConnectReq found no slot sas session open CAM");
	}

	SM_TRACE_RETURN(TRMOD_SAS, "SasConnectReq return\r\n");
	return;
}



/******************************************************************************
  函数名: SasSendMessage()
  描述:   发送async消息给CAM
  其他:
******************************************************************************/
static int SasSendMessage(ciehs_hsas_t sas_handle, unsigned char type, unsigned char* pu8Message, unsigned short u16Len)
{
	unsigned char* pu8APDU;
	unsigned int u32APDULen;
	static unsigned int u32Msgnb = 0;
	unsigned int u32Index;
	unsigned char u8Cmdid;

	if(SasCheckSessActive(s_stSas.m_astAppSess[sas_handle].m_u8Slotid, s_stSas.m_astAppSess[sas_handle].m_u16Ssnb))
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSendMessage() - found sas session invalid\r\n");
		return -1;
	}

	SM_TRACE_ENTRY(TRMOD_SAS, "SasSendMessage entry, sas_handle = %d, type = %d, pu8Message = %p, u16Len = %d\r\n", sas_handle, type, pu8Message, u16Len);
	SM_OsSemWait(&s_stSas.m_semLock, -1);
	if(sas_handle < CIEHS_SAS_MAX_SESSION_NUM)
	{
		u32APDULen = u16Len+9;//max: tag(3)+len(3)+msnb(1)+msgLen(2)
		pu8APDU = malloc(u32APDULen);
		if(pu8APDU)
		{
			asnWriteInt24(pu8APDU, CIEHS_SAS_TAG_ASYNC_MSG);
			u32Index = 3;
			u32Index += asnWriteApduLengthField(pu8APDU+3, u16Len+3);
			pu8APDU[u32Index] = u32Msgnb;
			u32Index++;
			asnWriteInt16(&pu8APDU[u32Index], u16Len);
			u32Index += 2;
			u32APDULen -= u32Index;
			memcpy(pu8APDU+u32Index, pu8Message, u16Len);
			u32Msgnb++;
			u32Index += u16Len;
			SendSasResourceAPDU(s_stSas.m_astAppSess[sas_handle].m_u8Slotid, s_stSas.m_astAppSess[sas_handle].m_u16Ssnb, pu8APDU, u32Index);
			free(pu8APDU);
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS, "SasSendMessage malloc memery fail\r\n");
		}
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasSendMessage found sas handle invalid\r\n");
	}
	SM_OsSemRelease(&s_stSas.m_semLock);

	SM_TRACE_RETURN(TRMOD_SAS, "SasSendMessage() - return\r\n");
	return 0;
}

/******************************************************************************
  函数名: SasDisconnect()
  描述:   断开SAS连接，并关闭会话
  其他:
******************************************************************************/
void SasDisconnect(unsigned short u16SlotId, short u16Ssnb)
{
	unsigned char i;
	SM_TRACE_ENTRY(TRMOD_SAS, "SasDisconnect() - entry\r\n");
	SM_OsSemWait(&s_stSas.m_semLock, -1);

	for(i=0; i<CIEHS_SAS_MAX_SESSION_NUM; i++)
	{
		if(s_stSas.m_astAppSess[i].m_u16Ssnb == u16Ssnb
			&& s_stSas.m_astAppSess[i].m_u8Slotid == u16SlotId)
		{
			s_stSas.m_astAppSess[i].m_eStatus = CIEHS_APP_SESS_FREE;
			break;
		}
	}
	
	SM_OsSemRelease(&s_stSas.m_semLock);
	SM_TRACE_RETURN(TRMOD_SAS, "SasDisconnect() - return\r\n");
}


static int SasCheckSessActive(unsigned short u16SlotId, short u16Ssnb)
{
	unsigned int index;
	int ret = -1;

	SM_TRACE_ENTRY(TRMOD_SAS, "SasCheckSessActive() - entry u32SlotId = %d, u32Ssnb = %d\r\n", u16SlotId, u16Ssnb);
	if(u16SlotId > MAXSLOTID)
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasCheckSessActive() - found u32SlotId error\r\n");
		return -1;
	}

	SM_OsSemWait(&s_stSas.m_semLock, -1);
	index = SasFindSessionIndex(u16SlotId, u16Ssnb);
	if(index != CIEHS_SAS_INVALID_SESSION_INDEX)
	{
		ret = 0;
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "SasCheckSessActive() -  session not found u16SlotId = %d, u16Ssnb = %d", u16SlotId, u16Ssnb);
	}
	SM_OsSemRelease(&s_stSas.m_semLock);

	SM_TRACE_RETURN(TRMOD_SAS, "SasCheckSessActive() -  return\r\n");
	return ret;
}


/******************************************************************************
  函数名: sas_init()
  描述:   注册回调、创建SAS相关线程
  其他:
******************************************************************************/
int sas_init(void)
{
	SM_TRACE_ENTRY(TRMOD_SAS, "sas_init() - entry\r\n");
	//register_cisas_get_info(cisas_get_cam_info);
	//register_cisas_get_dongle_hw(cisas_get_dongle_hw);
	//register_cisas_enable_mmi_status(cisas_enable_mmi_status);

	if(s_stSas.m_u8Init == 0)
	{
		memset(&s_stSas, 0, sizeof(s_stSas));
		SM_OsSemCreate(&s_stSas.m_semLock, NULL, 1);
		SM_OsSemCreate(&s_stSas.m_semSasTask, NULL, 1);
		SM_OsSemCreate(&s_semSasTuner, NULL, 1);
		SM_OsSemCreate(&s_semSasdongletype, NULL, 1);
		SM_OsSemCreate(&s_semSasPid, NULL, 1);
		SM_OsSemCreate(&s_semSasUpgrade, NULL, 1);
		SM_OsSemCreate(&s_semSasDongleHW, NULL, 1);
		SM_OsSemCreate(&s_semSasDongleMmi, NULL, 1);
		
		SM_CreateQueue(&s_queSasTuner, NULL);
		SM_CreateQueue(&s_queSasPid, NULL);
		SM_CreateQueue(&s_queSasUpgrade, NULL);
		SM_CreateQueue(&s_queSasDongleType, NULL);
		SM_CreateQueue(&s_queSasdonglHW, NULL);
		SM_CreateQueue(&s_queSasMmiAbility, NULL);
		s_stSas.m_u32SasTaskid = SM_CreateTask("sas", sas_task, NULL, NULL, 20*1024, 81, TRUE, SAS_TASK_AID);
		//registerPrivateResourceToAgent(CIEHS_SAS_RESOURCE_ID_V1, SasSessionOpenReq, SasAPDURecv, SasSessionCloseReq);
		s_stSas.m_u8Init = 1;
		SM_TRACE_INFO(TRMOD_SAS, "sas_init finish\r\n");
	}
	else
	{
		SM_TRACE_ERROR(TRMOD_SAS, "sas_init have run\r\n");
		return 1;
	}
	
	SM_TRACE_RETURN(TRMOD_SAS, "sas_init() - return\r\n");
	return 0;
}


int sas_on_message(xmsg_t* pXmsg)
{
	xmsg_t xmsg;
	unsigned short ssnb;
	unsigned char tcid;

	switch (pXmsg->m_type)
	{
	case APP_OPEN_SS_REQ:
		ssnb = pXmsg->m_bd.m_app_open_ss_req.m_ssnb;
		tcid = pXmsg->m_bd.m_app_open_ss_req.m_tcid;
		SM_TRACE_INFO(TRMOD_SAS, "private_resource_on_message() - APP_OPEN_SS_REQ received, ssnb=%d\r\n", ssnb);
		memset(&xmsg,0x00,sizeof(xmsg_t));
		xmsg.m_sndrcver = (RM << 4) | RM;
		xmsg.m_type = APP_OPEN_SS_RSP;
		xmsg.m_bd.m_app_open_ss_rsp.m_tcid = tcid;
		xmsg.m_bd.m_app_open_ss_rsp.m_ssnb = ssnb;
		xmsg.m_bd.m_app_open_ss_rsp.m_ressId = pXmsg->m_bd.m_app_open_ss_req.m_ressId;
		xmsg.m_bd.m_app_open_ss_rsp.m_status = OK; //SasSessionOpenReq(0, ssnb);

		SM_TRACE_INFO(TRMOD_SAS, "sas_on_message() - will send APP_OPEN_SS_RSP to PROXY\r\n");
		ITC_SendXmsg(&xmsg);
		
		SasSessionOpenReq(0, ssnb);
		break;
	case APP_SS_BROKEN:
		ssnb = pXmsg->m_bd.m_app_ss_broken.m_ssnb;
		SasSessionCloseReq(0, ssnb);
		break;
	case APP_TMPEND:
		ssnb = (unsigned short)pXmsg->m_bd.m_timer.m_param;
		memset(&xmsg, 0x00, sizeof(xmsg));
		xmsg.m_sndrcver = (RM << 4) | RM;
		xmsg.m_type  = APP_CLOSE_SS_REQ;
		xmsg.m_bd.m_app_close_ss_req.m_ssnb = ssnb;
		SM_TRACE_INFO(TRMOD_SAS, "sas_on_message() - is timer event, will send APP_CLOSE_SS_REQ to PROXY, ssnb=%d\r\n", ssnb);
		SasSessionCloseReq(0, ssnb);
		ITC_SendXmsg(&xmsg);
		break;
	case APP_APDU:
		SasAPDURecv(0, pXmsg->m_bd.m_app_apdu.m_ssnb, pXmsg->m_bd.m_app_apdu.m_pbApdu);
		break;
	default:
		break;
	}
	return 0;
}


int sas_task(void* pParam)
{
	unsigned int rc = 0;
	unsigned int u32MsgLen;
	sas_msg_t stMsg;

	SM_TRACE_ENTRY(TRMOD_SAS, "sas_task entry pParam = %p\r\n", pParam);

	//SM_OsSemWait(&s_stSas.m_semSasTask, -1);
	SM_TRACE_INFO(TRMOD_SAS, "sas_task start\r\n");
	while(s_stSas.m_u8ExitFlag != 1)
	{
		memset(&stMsg, 0, sizeof(stMsg));
		if(SM_ReceiveQueueByTaskid(s_stSas.m_u32SasTaskid, &stMsg, -1))
		{
			switch(stMsg.m_eType)
			{
			case CIEHS_SAS_MESSAGE_TYPE_CONNECT:
				//spare session
				SasSessConnect(stMsg.m_u8Slotnb, stMsg.m_u16Ssnb);
				if(s_sasConnected == 0)
				{
					SM_Sleep(100);
					SasSendConnectReqAPDU(stMsg.m_u8Slotnb, sasAppId, 0); // connect to SAS application ASAP
					s_sasConnected = 1;
					if(pfSasSessionConnectedCb)
						pfSasSessionConnectedCb(0);   //0为成功，1为失败
				}
				break;
			case CIEHS_SAS_MESSAGE_TYPE_DATA:		//添加输出dangle信息
				SasSessParseAPDU(stMsg.m_u8Slotnb, stMsg.m_u16Ssnb, stMsg.m_pu8Apdu, stMsg.m_u32ApduLen);
				free(stMsg.m_pu8Apdu);
				break;
			case CIEHS_SAS_MESSAGE_TYPE_CLOSE://application close
				SM_TRACE_ERROR(TRMOD_SAS, "sas_task receive close session APDU, stMsg.m_u8Slotnb = %d, stMsg.m_u16Ssnb = %d\r\n", stMsg.m_u8Slotnb, stMsg.m_u16Ssnb);
				SasSessClose(stMsg.m_u8Slotnb, stMsg.m_u16Ssnb);
				//SasDisconnect(stMsg.m_u8Slotnb, stMsg.m_u16Ssnb);
				s_sasConnected = 0;
				break;
			default:
				SM_TRACE_ERROR(TRMOD_SAS, "hc_task recv unknowed msg\r\n");
				break;
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS, "sas_task recv msg error\r\n");
		}
	}
	//SM_OsSemDestroy(&s_stSas.m_semSasTask);
	SM_TRACE_RETURN(TRMOD_SAS, "sas_task return\r\n");
	return 0;
}

int SasRegisterSasConnectedNotify(pfSasSessionConnected callback)
{
	pfSasSessionConnectedCb = callback;
	return 1;
}

int cisas_reset_tuner(void)
{
	unsigned char msgbyte[8];
	int ret = -1;
	sas_async_message_t sas_async_msg;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}

	SM_OsSemWait(&s_semSasTuner, -1);

	asnWriteInt16(msgbyte, SAS_TUNER_RESET); // tag
	asnWriteInt16(msgbyte+2, 4); // length	
	memcpy(msgbyte+4, "REST", 4);	

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_reset_tuner() - sent reset tuner command to CAM\r\n");

	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		SM_OsSemRelease(&s_semSasTuner);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasTuner, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_reset_tuner() - received queue\r\n");
			if(sas_async_msg.m_u16Tag == SAS_TUNER_RESET_RSP && sas_async_msg.m_u16Len == 4)
			{
				ret = asnReadInt32(sas_async_msg.m_msgBuf);
				free(sas_async_msg.m_msgBuf);
				SM_TRACE_INFO(TRMOD_SAS, "cisas_reset_tuner() - receive reset tuner response successfully\r\n");
				break;
			}
			else
			{
				SM_TRACE_INFO(TRMOD_SAS, "cisas_reset_tuner() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_reset_tuner() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}

		SM_TRACE_INFO(TRMOD_SAS, "cisas_reset_tuner() - loop again\r\n");
	}

	SM_OsSemRelease(&s_semSasTuner);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_reset_tuner() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_tuner_lock(dvb_tuner_t tune_params)
{
	unsigned char* msgbyte = NULL;
	unsigned short len = sizeof(dvb_tuner_t);
	sas_async_message_t sas_async_msg;
	int ret = -1;
	unsigned int u32TryTimes = 0;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}

	SM_TRACE_ENTRY(TRMOD_SAS,"cisas_tuner_lock() - entry\r\n");

	SM_OsSemWait(&s_semSasTuner, -1);

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_tuner_lock() - sent to CAM freq = %d, sym_rate = %d, QAM = %d, bandwidth = %d\r\n", 
		tune_params.frequency, tune_params.symbol_rate, tune_params.modulation, tune_params.bandwidth);

	msgbyte = (unsigned char*)malloc(len+4);
	memset(msgbyte, 0, len+4);

	asnWriteInt16(msgbyte, SAS_TUNER_LOCK); // tag
	asnWriteInt16(msgbyte+2, len); // length
	memcpy(msgbyte+4, &tune_params, len);

	if(SasSendMessage(0, 0, msgbyte, len+4))
	{
		free(msgbyte);
		SM_OsSemRelease(&s_semSasTuner);
		return -1;
	}
	free(msgbyte);

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasTuner, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			if(sas_async_msg.m_u16Tag == SAS_TUNER_LOCK_RSP && sas_async_msg.m_u16Len == 4)
			{
				ret = asnReadInt32(sas_async_msg.m_msgBuf);
				free(sas_async_msg.m_msgBuf);
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_tuner_lock() - receive response successfully, ret = %d\r\n", ret);
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_tuner_lock() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_tuner_lock() - can not receive queue after timeout! u32TryTimes = %d\r\n", u32TryTimes);
			u32TryTimes++;
			if(s_sasConnected!=0 && u32TryTimes<3)
			{
				SM_TRACE_ERROR(TRMOD_SAS,"cisas_tuner_lock() - try receive again\r\n");
				continue;
			}
			else
			{
				SM_TRACE_ERROR(TRMOD_SAS,"cisas_tuner_lock() - try %d time still can not receive queue or sas interupt s_sasConnected = %d\r\n", u32TryTimes, s_sasConnected);
				ret = -1;
				break;
			}
		}
	}

	SM_OsSemRelease(&s_semSasTuner);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_tuner_lock() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_get_tuner_status(dvb_tuner_status_t* tuner_status)
{
	unsigned char msgbyte[8];
	unsigned short len = sizeof(dvb_tuner_status_t);
	sas_async_message_t sas_async_msg;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}	

	SM_TRACE_ENTRY(TRMOD_SAS,"cisas_get_tuner_status() - entry\r\n");

	SM_OsSemWait(&s_semSasTuner, -1);

	asnWriteInt16(msgbyte, SAS_GET_TUNER_STATUS); // tag
	asnWriteInt16(msgbyte+2, 4); // length
	memcpy(msgbyte+4, "GSTA", 4);

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_tuner_status() - sent get tuner status to CAM\r\n");
	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		SM_OsSemRelease(&s_semSasTuner);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasTuner, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			if(sas_async_msg.m_u16Tag == SAS_TUNER_STATUS)
			{
				memcpy(tuner_status, sas_async_msg.m_msgBuf, sas_async_msg.m_u16Len);
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_tuner_status() - receive response successfully, freq = %d, sym[%d], QAM[%d], lock status = %d, snr = %d, level = %d\r\n",
					tuner_status->frequency, tuner_status->symbol_rate, tuner_status->modulation, tuner_status->bLock, tuner_status->snr, tuner_status->level);
				free(sas_async_msg.m_msgBuf);
				ret = 0;
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_tuner_status() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_get_tuner_status() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}
	}

	SM_OsSemRelease(&s_semSasTuner);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_get_tuner_status() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_tuner_standby(void)
{
	unsigned char msgbyte[8];
	int ret = -1;
	sas_async_message_t sas_async_msg;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}

	SM_OsSemWait(&s_semSasTuner, -1);

	asnWriteInt16(msgbyte, SAS_TUNER_STANDBY); // tag
	asnWriteInt16(msgbyte+2, 4); // length	
	memcpy(msgbyte+4, "STBY", 4);	

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_tuner_standby() - sent  tuner standby command to CAM\r\n");

	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		SM_OsSemRelease(&s_semSasTuner);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasTuner, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_tuner_standby() - received queue\r\n");
			if(sas_async_msg.m_u16Tag == SAS_TUNER_STANDBY_RSP && sas_async_msg.m_u16Len == 4)
			{
				ret = asnReadInt32(sas_async_msg.m_msgBuf);
				free(sas_async_msg.m_msgBuf);
				SM_TRACE_INFO(TRMOD_SAS, "cisas_tuner_standby() - receive reset tuner response successfully\r\n");
				break;
			}
			else
			{
				SM_TRACE_INFO(TRMOD_SAS, "cisas_tuner_standby() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_tuner_standby() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}

		SM_TRACE_INFO(TRMOD_SAS, "cisas_tuner_standby() - loop again\r\n");
	}

	SM_OsSemRelease(&s_semSasTuner);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_tuner_standby() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_tuner_resume(void)
{
	unsigned char msgbyte[8];
	int ret = -1;
	sas_async_message_t sas_async_msg;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}

	SM_OsSemWait(&s_semSasTuner, -1);

	asnWriteInt16(msgbyte, SAS_TUNER_RESUME); // tag
	asnWriteInt16(msgbyte+2, 4); // length	
	memcpy(msgbyte+4, "RESU", 4);	

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_tuner_resume() - sent  tuner standby command to CAM\r\n");

	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		SM_OsSemRelease(&s_semSasTuner);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasTuner, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_tuner_resume() - received queue\r\n");
			if(sas_async_msg.m_u16Tag == SAS_TUNER_RESUME_RSP && sas_async_msg.m_u16Len == 4)
			{
				ret = asnReadInt32(sas_async_msg.m_msgBuf);
				free(sas_async_msg.m_msgBuf);
				SM_TRACE_INFO(TRMOD_SAS, "cisas_tuner_resume() - receive reset tuner response successfully\r\n");
				break;
			}
			else
			{
				SM_TRACE_INFO(TRMOD_SAS, "cisas_tuner_resume() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_tuner_resume() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}

		SM_TRACE_INFO(TRMOD_SAS, "cisas_tuner_resume() - loop again\r\n");
	}

	SM_OsSemRelease(&s_semSasTuner);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_tuner_resume() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_pid_black_list (unsigned short *pid_buf, unsigned short buf_len, unsigned short pid_cnt)
{
	unsigned char *msgbyte = NULL;
	sas_async_message_t sas_async_msg;
	unsigned short u16Index = 0;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}

	SM_TRACE_ENTRY(TRMOD_SAS,"cisas_pid_black_list() - entry\r\n");
	SM_OsSemWait(&s_semSasPid, -1);

	msgbyte = (unsigned char*)malloc(buf_len+6);

	asnWriteInt16(msgbyte, SAS_PID_LIST); // tag
	asnWriteInt16(msgbyte+u16Index, buf_len);
	u16Index += 2;
	asnWriteInt16(msgbyte+u16Index, pid_cnt);
	u16Index += 2;
	memcpy(msgbyte+u16Index, pid_buf, buf_len);
	u16Index += buf_len;

	if(SasSendMessage(0, 0, msgbyte, u16Index))
	{
		free(msgbyte);
		SM_OsSemRelease(&s_semSasPid);
		return -1;
	}	
	free(msgbyte);

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasPid, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_pid_black_list() - received queue\r\n");
			if(sas_async_msg.m_u16Tag == SAS_PID_LIST_RSP && sas_async_msg.m_u16Len == 4)
			{
				ret = asnReadInt32(sas_async_msg.m_msgBuf);
				free(sas_async_msg.m_msgBuf);
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_pid_black_list() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}			
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_pid_black_list() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}
	}

	SM_OsSemRelease(&s_semSasPid);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_pid_black_list() - return, ret = %d\r\n", ret);
	return ret;
}

int cisas_send_printlog_data(const unsigned char* data_buf, unsigned short data_len)
{
	unsigned char *msgbyte = NULL;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}	

	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_send_printlog_data() - entry\r\n");
//	SM_OsSemWait(&s_stSas.m_semSasTask, -1);

	msgbyte = (unsigned char*)malloc(data_len+4);

	asnWriteInt16(msgbyte, SAS_PRINTLOG_DATA);
	asnWriteInt16(msgbyte+2, data_len);
	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_send_printlog_data() - 1\r\n");
	memcpy(msgbyte+4, data_buf, data_len);
	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_send_printlog_data() -data_buf = %s\r\n",data_buf);
	//SasSendMessage(0, 0, msgbyte, data_len+4);
	if(SasSendMessage(0, 0, msgbyte, data_len+4))
	{
		SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_send_printlog_data() - 3\r\n");
		free(msgbyte);
		return -1;
	}
	free(msgbyte);

//	SM_OsSemRelease(&s_stSas.m_semSasTask);
	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_send_printlog_data() - return\r\n");

	return 0;
}

int cisas_get_cam_info(char *cam_info_buf)
{
	unsigned char msgbyte[8];
	sas_async_message_t sas_async_msg;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}

	SM_TRACE_ENTRY(TRMOD_SAS,"cisas_get_cam_info() - entry\r\n");

	if(SM_ReceiveQueue(&s_queSasPid, &sas_async_msg, 0)) 
	{
		SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_cam_info() - received previous CAM info\r\n");
	}

	asnWriteInt16(msgbyte, SAS_GET_CAM_INFO); // tag
	asnWriteInt16(msgbyte+2, 4); // length
	memcpy(msgbyte+4, "GCIN", 4);

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_cam_info() - sent get CAM info to CAM\r\n");
	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasPid, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			if(sas_async_msg.m_u16Tag == SAS_CAM_INFO_RSP)
			{
				memcpy(cam_info_buf, sas_async_msg.m_msgBuf, sas_async_msg.m_u16Len);
				if(strlen(cam_info_buf) <= 10)
				{
					strcpy(cam_info_buf, "暂无信息##暂无信息##暂无信息");
				}
				else
					cam_info_buf[sas_async_msg.m_u16Len] = 0;
				
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_cam_info() - receive response successfully\r\n");
				free(sas_async_msg.m_msgBuf);
				ret = 0;
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_cam_info() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_get_cam_info() - can not receive queue after timeout!\r\n");
			strcpy(cam_info_buf, "暂无信息##暂无信息##暂无信息");
			ret = -1;
			break;
		}
	}
	//SM_OsSemRelease(&s_semSasTuner);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_get_cam_info() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_send_upgrade_data(const unsigned char* data_buf, unsigned short data_len)
{
	unsigned char *msgbyte = NULL;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}	
	
	SM_TRACE_ENTRY(TRMOD_SAS,"cisas_send_upgrade_data() - entry\r\n");
//	SM_OsSemWait(&s_stSas.m_semSasTask, -1);

	msgbyte = (unsigned char*)malloc(data_len+4);
	
	asnWriteInt16(msgbyte, SAS_UPGRADE_DATA);
	asnWriteInt16(msgbyte+2, data_len);
	memcpy(msgbyte+4, data_buf, data_len);

	//SasSendMessage(0, 0, msgbyte, data_len+4);
	if(SasSendMessage(0, 0, msgbyte, data_len+4))
	{
		free(msgbyte);
		return -1;
	}	
	free(msgbyte);

//	SM_OsSemRelease(&s_stSas.m_semSasTask);
	SM_TRACE_RETURN(TRMOD_SAS,"cisas_send_upgrade_data() - return\r\n");

	return 0;
}


int cisas_get_upgrade_status(unsigned char* data_buf, unsigned short *data_len)
{
	sas_async_message_t sas_async_msg;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		SM_Sleep(1000);
		return -1;
	}	
	
	SM_TRACE_ENTRY(TRMOD_SAS,"cisas_get_upgrade_status() - entry\r\n");
	//SM_OsSemWait(&s_semSasUpgrade, -1);

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasUpgrade, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_upgrade_status() - received queue\r\n");
			if(sas_async_msg.m_u16Tag == SAS_UPGRADE_DATA_RSP)
			{
				memcpy(data_buf, sas_async_msg.m_msgBuf, sas_async_msg.m_u16Len);
				*data_len = sas_async_msg.m_u16Len;
				free(sas_async_msg.m_msgBuf);
				ret = 0;
				break;
			}
			else
			{
				SM_TRACE_INFO(TRMOD_SAS, "cisas_get_upgrade_status() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}			
		}
		if(SasCheckSessActive(s_stSas.m_astAppSess[0].m_u8Slotid, s_stSas.m_astAppSess[0].m_u16Ssnb))
		{
			SM_TRACE_ERROR(TRMOD_SAS, "cisas_get_upgrade_status() - found sas session invalid\r\n");
			break;
		}	
		SM_TRACE_INFO(TRMOD_SAS, "cisas_get_upgrade_status() - loop again\r\n");
	}

	//SM_OsSemRelease(&s_semSasUpgrade);
	SM_TRACE_RETURN(TRMOD_SAS,"cisas_get_upgrade_status() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_get_dongle_type(char* dongle_type_str)
{
	unsigned char msgbyte[8];
	unsigned short len = sizeof(dvb_tuner_status_t);
	sas_async_message_t sas_async_msg;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}	

	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_get_dongle_type() - entry\r\n");

	SM_OsSemWait(&s_semSasdongletype, -1);


	asnWriteInt16(msgbyte, SAS_GET_DONGLE_TYPE); // tag
	asnWriteInt16(msgbyte+2, 4); // length
	memcpy(msgbyte+4, "GTYP", 4);

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_dongle_type() - Get Dongle type from CAM\r\n");
	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		SM_OsSemRelease(&s_semSasdongletype);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasDongleType, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			if(sas_async_msg.m_u16Tag == SAS_GET_DONGLE_TYPE_RSP)
			{
				memcpy(dongle_type_str, sas_async_msg.m_msgBuf, sas_async_msg.m_u16Len);
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_dongle_type() - receive dongle type successed,%s\r\n",dongle_type_str);
				free(sas_async_msg.m_msgBuf);
				ret = 0;
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_dongle_type() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_get_dongle_type() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}
	}

	SM_OsSemRelease(&s_semSasdongletype);

	SM_TRACE_RETURN(TRMOD_SAS,"cisas_get_dongle_type() - return, ret = %d\r\n", ret);
	return ret;
}


int cisas_get_dongle_hw(char* dongle_hw_str, unsigned short *data_len)
{
	unsigned char msgbyte[8];
	sas_async_message_t sas_async_msg;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}	

	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_get_dongle_hw() - entry\r\n");

	SM_OsSemWait(&s_semSasDongleHW, -1);

	asnWriteInt16(msgbyte, SAS_GET_DGL_HW); // tag
	asnWriteInt16(msgbyte+2, 4); // length
	memcpy(msgbyte+4, "GDHW", 4);

	SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_dongle_hw() - Get Dongle Hw from CAM\r\n");
	if(SasSendMessage(0, 0, msgbyte, 8))
	{
		SM_OsSemRelease(&s_semSasdongletype);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasdonglHW, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			if(sas_async_msg.m_u16Tag == SAS_DGL_HW_RSP)
			{
				memcpy(dongle_hw_str, sas_async_msg.m_msgBuf, sas_async_msg.m_u16Len);
				*data_len = sas_async_msg.m_u16Len;
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_dongle_hw() - receive dongle_hw_str successed,%s\r\n",dongle_hw_str);
				free(sas_async_msg.m_msgBuf);
				ret = 0;
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_get_dongle_hw() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_get_dongle_hw() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}
	}

	SM_OsSemRelease(&s_semSasDongleHW);
	SM_TRACE_RETURN(TRMOD_SAS,"cisas_get_dongle_hw() - return, ret = %d\r\n", ret);
	return ret;
}

int cisas_enable_mmi_status(char* enableflag, char* mmi_type, char* mmi_status_str)
{
	unsigned char msgbyte[8];
	sas_async_message_t sas_async_msg;
	int ret = -1;

	if(s_sasConnected == 0) 
	{
		SM_TRACE_ERROR(TRMOD_SAS, "%s - SAS is not ready\r\n", __FUNCTION__);
		return -1;
	}	

	SM_TRACE_NOTIFY(TRMOD_SAS,"cisas_enable_mmi_status() - entry\r\n");
	SM_OsSemWait(&s_semSasDongleMmi, -1);

	asnWriteInt16(msgbyte, SAS_ENL_CUS_MM); // tag
	asnWriteInt16(msgbyte+2, 2); // length
	memcpy(msgbyte+4, enableflag, 1);
	memcpy(msgbyte+5, mmi_type, 1);

	//SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_enable_mmi_status() - Enale Mmi to CAM\r\n");
	SM_TRACE_BYTES(TRMOD_SAS, TRLEV_NOTIFY, msgbyte, 6, "cisas_enable_mmi_status() - enable data is:");
	if(SasSendMessage(0, 0, msgbyte, 6))
	{
		SM_OsSemRelease(&s_semSasDongleMmi);
		return -1;
	}

	while(1)
	{
		if(SM_ReceiveQueue(&s_queSasMmiAbility, &sas_async_msg, SAS_RSP_TIMEOUT)) // wait reply
		{
			if(sas_async_msg.m_u16Tag == SAS_CUS_MMI_RSP)
			{
				memcpy(mmi_status_str, sas_async_msg.m_msgBuf, sas_async_msg.m_u16Len);
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_enable_mmi_status() - receive mmi_status_str successed, type is %d\r\n",mmi_status_str[0]);
				free(sas_async_msg.m_msgBuf);
				ret = 0;
				break;
			}
			else
			{
				SM_TRACE_NOTIFY(TRMOD_SAS, "cisas_enable_mmi_status() - wrong response\r\n");
				free(sas_async_msg.m_msgBuf);
			}
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_SAS,"cisas_enable_mmi_status() - can not receive queue after timeout!\r\n");
			ret = -1;
			break;
		}
	}

	SM_OsSemRelease(&s_semSasDongleMmi);
	SM_TRACE_RETURN(TRMOD_SAS,"cisas_enable_mmi_status() - return, ret = %d\r\n", ret);
	return ret;
}




